﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace Atendex.Dominio
{
    /// <summary>
    /// Provê métodos criptográficos simples.
    /// </summary>
    public class Cryptex
    {
        private static string chavePadrao = "atendexcomputex";

        private static byte[] ChavePadraoBytes(int szInBits)
        {
            byte[] bytesChaveAES = new byte[szInBits / 8];
            byte[] bytesChavePadrao = Encoding.ASCII.GetBytes(chavePadrao);
            Array.Copy(bytesChavePadrao, bytesChaveAES, Math.Min(bytesChavePadrao.Length, bytesChaveAES.Length));
            return bytesChaveAES;
        }

        /// <summary>
        /// Encripta uma string sob uma chave padrão. Não deve ser utilizada como
        /// provedor de confidencialidade.
        /// </summary>
        /// <param name="textoClaro">a string a ser cifrada</param>
        /// <returns>o texto cifrado</returns>
        public static string EncriptaChavePadrao(string textoClaro)
        {

            MemoryStream msEncrypt = null;
            RijndaelManaged aesAlg = null;

            try
            {
                // Create a RijndaelManaged object
                // with the specified key and IV.
                aesAlg = new RijndaelManaged();
                aesAlg.KeySize = 256;
                aesAlg.Key = ChavePadraoBytes(256);
                aesAlg.IV = new byte[128/8];

                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
                msEncrypt = new MemoryStream();
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        swEncrypt.Write(textoClaro);
                    }
                }
            }
            finally
            {

                // Clear the RijndaelManaged object.
                if (aesAlg != null)
                    aesAlg.Clear();
            }

            return ToByteString(msEncrypt.ToArray());
        }

        public static string DecriptaChavePadrao(string textoCifrado)
        {
            byte[] bytesTextoCifrado = null;
            try
            {
                bytesTextoCifrado = ToByteArray(textoCifrado);
            }
            catch (Exception e)
            {
                throw new CryptexException("Erro ao decodifcar string",e);
            }
            // Declare the RijndaelManaged object
            // used to decrypt the data.
            RijndaelManaged aesAlg = null;

            // Declare the string used to hold
            // the decrypted text.
            string plaintext = null;

            try
            {
                // Create a RijndaelManaged object
                // with the specified key and IV.
                aesAlg = new RijndaelManaged();
                aesAlg.KeySize = 256;
                aesAlg.Key = ChavePadraoBytes(256);
                aesAlg.IV = new byte[128 / 8];


                // Create a decrytor to perform the stream transform.
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
                // Create the streams used for decryption.
                using (MemoryStream msDecrypt = new MemoryStream(bytesTextoCifrado))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))

                            // Read the decrypted bytes from the decrypting stream
                            // and place them in a string.
                                plaintext = srDecrypt.ReadToEnd();
                            
                    }
                }

            }
            catch (Exception e)
            {
                throw new CryptexException("Erro ao decifrar", e);
            }
            finally
            {

                // Clear the RijndaelManaged object.
                if (aesAlg != null)
                    aesAlg.Clear();
            }

            return plaintext;
        }

        public static byte[] ToByteArray(string HexString)
        {
            int NumberChars = HexString.Length;
            byte[] bytes = new byte[NumberChars / 2];
            for (int i = 0; i < NumberChars; i += 2)
            {
                bytes[i / 2] = Convert.ToByte(HexString.Substring(i, 2), 16);
            } return bytes;
        }

        private static string ToByteString(byte[] value)
        {
            StringBuilder stringBuilder = new StringBuilder();
            string hexAlphabet = "0123456789ABCDEF";
            if (value != null)
            {
                foreach (byte b in value)
                {
                    stringBuilder.Append(hexAlphabet[(int)(b >> 4)]);
                    stringBuilder.Append(hexAlphabet[(int)(b & 0xF)]);
                }
            }
            return stringBuilder.ToString();
        }

    }
}
